import { PU1_TABLE, PU2_TABLE } from "./config"
import { getBinary, getBuffer, permutation, to16 } from "./utils"

interface IGropKey {
  C: string
  D: string
}

/**
 * 使用 自定义的密钥 生成主密钥，在使用主密钥生成子密钥组
 * @param key 自定义的密钥
 * @returns 生成的主密钥，16位，16进制数
 */
function init(key: string) {
  const buffer = getBuffer(key)
  const newbBuffer = Uint8Array.prototype.slice.call(buffer)
  const mainKey = newbBuffer.slice(0, 8)
  let result = ''
  for (let i = 0; i < mainKey.length; i++) {
    result += to16(mainKey[i])
  }

  return result
}

/**
 * 子密钥构造工厂
 * @param binary 主密钥二进制字符串，64位2进制数
 * @returns 子密钥数组
 */
function constructioner(binary: string) {
  // 进行 PC1 置换
  // const k_plus = pc1Handle(binary)

  // PC1 置换
  const k_plus = permutation(binary, PU1_TABLE)

  const C0 = k_plus.substring(0, k_plus.length / 2)
  const D0 = k_plus.substring(k_plus.length / 2)

  // 生成密钥对
  const groupKeys = structure16GroupKeys(C0, D0)

  // 生成子密钥
  const subKeys = groupKeysToKeys(groupKeys)

  return subKeys
}

/**
 * 构造 16 个密钥对
 * @param C0 
 * @param D0 
 * @returns 密钥对数组 {C: string, D: string}
 */
function structure16GroupKeys(C0: string, D0: string) {
  const groupKeys: IGropKey[] = []
  // 定义每次迭代的作用 动作
  const relus = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

  relus.forEach((relu, index) => {
    const iteration = index + 1
    let result: IGropKey = { C: '', D: '' }
    if (iteration !== 1) {

      // @ts-ignore
      const C = groupKeys[index - 1].C
      // @ts-ignore
      const D = groupKeys[index - 1].D

      result = leftShift(C, D, relu)

    } else {
      // 第一次迭代 使用 C0,D0
      result = leftShift(C0, D0, relu)
    }

    // @ts-ignore
    groupKeys.push(result)
  })

  return groupKeys
}

/**
 * 二进制左移函数
 * @param C 
 * @param D 
 * @param size 左移位数，返回密钥对
 * @returns 
 */
function leftShift(C: string, D: string, size: number): IGropKey {
  // 移动 C
  const sub_C = C.substring(0, size)
  const result_C = (C + sub_C).substring(size)
  // 移动 D
  const sub_D = D.substring(0, size)
  const result_D = (D + sub_D).substring(size)

  return {
    C: result_C,
    D: result_D
  }
}

// 密钥对转密钥
function groupKeysToKeys(groupKeys: IGropKey[]) {
  const keys: string[] = []

  groupKeys.forEach((item, index) => {
    // @ts-ignore
    const CD = item.C + item.D
    let k = ''
    PU2_TABLE.forEach(n => {
      k += CD.substring(n - 1, n)
    })
    keys.push(k)
  })

  return keys
}

// 创建 子密钥数组
export function createSubkeys(key: string) {
  // 主密钥，长度为 16的16进制数
  const mainKey = init(key)

  // 将主密钥转为2进制。64位2进制数
  const binary = getBinary(mainKey)

  // 子密钥数组
  const subkeys = constructioner(binary)

  return subkeys
}
